package machiavelli;
import java.util.*;

public class IteratoreElementiMano {
	protected ArrayList<Carta> mano;
	protected boolean hasNext;
	protected int[] combinazioni;
	
	protected final int LIMITE_COMBINAZIONI = 2000000;
	protected int combinazioniTrovate;
	protected final int DEFAULT_K = 20;
	
	long count = 0;
	
	protected int k;
	protected int n;
	
	public IteratoreElementiMano(int limiteCombinazioni){
		mano = new ArrayList<Carta>();
		combinazioniTrovate = 0;
	}
	
	public ArrayList<Carta> getMano() {
		return mano;
	}

	public void setMano(ArrayList<Carta> mano) {
		this.mano = mano;
	}

	public void init(){
		n = mano.size();
		k = Math.min(n, DEFAULT_K);
		init(n,k);
		hasNext = true;
	}
	public int getK() {
		return k;
	}

	protected void init(int n, int k){
		this.k = k;
		combinazioni = new int[k];
		for (int i=0; i<k; i++)
			combinazioni[i] = i+1;
		combinazioni[k-1]--;
	}
	protected void overflow(){
		System.out.println("overflow! "+k);
		k = Math.max(k/2,1);
		combinazioniTrovate=0;
		System.out.println("new k "+k);
	}
	
	protected boolean hasNext(){
		return k>0;
	}

	public ArrayList<Carta> next(){
		count++;
		if ((count % 500000) == 0) System.out.println("Combinazioni viste "+count);
		if (combinazioniTrovate++==LIMITE_COMBINAZIONI) overflow();
		if (!hasNext()) return null;
		if (generateTutteLeCombinazioni()){
			k--;
			if (k==0) return null;
			init(n,k);
		}
		int[] r = increment(k-1);
		if (r==null) return null;
		ArrayList<Carta> c = new ArrayList<Carta>();
		for (int i=0; i<r.length; i++)
			c.add(mano.get(r[i]-1));
		return c;
	}
	protected boolean generateTutteLeCombinazioni(){
		for (int i=0; i<k; i++)
			if (combinazioni[i]<max(i)) return false;
		return true;
	}
	
	protected int[] increment(int i){
		if (i<0) return null;
		combinazioni[i]++;
		if (combinazioni[i]>max(i)){
			increment(i-1);
			combinazioni[i] = combinazioni[i-1]+1;
		}
		return combinazioni;
	}

	protected int min(int i){
		return i+1;
	}
	protected int max(int i){
		return n-k+1+i;
	}
}
